#include "HatSectionNumericalCalculator.h"

#include "DataStructure/Common/Real.h"

#include "SectionCalculator/StandardSectionTool.h"
using SG::Algebra::Point;
using SG::DataStructure::Common::Real;
using SG::DataStructure::FEM::PBARLData;
using SG::FEMSolver::Element::HatSectionNumericalCalculator;

void HatSectionNumericalCalculator::Mesh (const PBARLData& section, _OUT Meshes& meshes, int refineLevel) const
{
    Real w4{ section.m_dimension[0] };
    Real t1{ section.m_dimension[1] };
    Real t2{ t1 };
    Real t3{ t1 };
    Real t4{ t1 };
    Real t5{ t1 };
    Real w3{ section.m_dimension[2] };
    Real w1{ t4 + section.m_dimension[3] };
    Real w2{ t5 + section.m_dimension[3] };

    int n = refineLevel + 1;

    StandardSectionTool secMesh;
    Point               point;
    int                 nodeId{ 0 };
    int                 eleId{ 0 };
    Meshes              newMeshes;
    NodeSet             newEdgeNodes;
    int                 numRepeatNodes{ 0 };
    NodeSet             edgeNodes;

    // 1st block
    point.m_y = 0.0;
    point.m_z = 0.0;
    secMesh.MeshRect (point, w1 - t4, t1, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 2nd block
    point.m_y = w1;
    point.m_z = 0.0;
    secMesh.MeshRect (point, -t4, t1, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 3rd block
    point.m_y = w1 - t4;
    point.m_z = w4 - t3;
    secMesh.MeshRect2 (point, t4, -(w4 - t3 - t1), n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 4th block
    point.m_y = w1 - t4;
    point.m_z = w4;
    secMesh.MeshRect2 (point, t4, -t3, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 5th block
    point.m_y = w1 + (w3 - t4 - t5);
    point.m_z = w4 - t3;
    secMesh.MeshRect (point, -(w3 - t4 - t5), t3, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 6th block
    point.m_y = w1 + (w3 - t4);
    point.m_z = w4 - t3;
    secMesh.MeshRect (point, -t5, t3, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 7th block
    point.m_y = w1 + (w3 - t4 - t5);
    point.m_z = t2;
    secMesh.MeshRect2 (point, t5, w4 - t2 - t3, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 8th block
    point.m_y = w1 + (w3 - t4 - t5);
    point.m_z = 0.0;
    secMesh.MeshRect2 (point, t5, t2, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);

    // 9th block
    point.m_y = w1 + w2 + (w3 - t4 - t5);
    point.m_z = 0.0;
    secMesh.MeshRect (point, -(w2 - t5), t2, n, n, nodeId, eleId, _OUT newMeshes, _OUT newEdgeNodes);
    numRepeatNodes = 2 * n + 1;
    secMesh.Merge (edgeNodes, numRepeatNodes, newMeshes, meshes, nodeId, eleId);
    secMesh.UpdateEdgeNodes (newEdgeNodes, numRepeatNodes, edgeNodes);
}